package clock.socoolby.com.clock.widget.animatorview.animator.textanimator;


import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextPaint;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import clock.socoolby.com.clock.widget.animatorview.AbstractAnimator;
import clock.socoolby.com.clock.widget.animatorview.I_AnimatorEntry;

//参考自:https://github.com/HpWens/MeiWidgetView/blob/master/widget/src/main/java/com/meis/widget/evaporate/
public class EvaporateTextAnimator extends AbstractAnimator<EvaporateTextAnimator.EvaporateText> {

    public EvaporateTextAnimator() {
        super(1);
    }

    @Override
    public EvaporateText createNewEntry() {
        return new EvaporateText();
    }

    @Override
    public int dialyTime() {
        return 15;
    }

    public class EvaporateText implements I_AnimatorEntry {
        protected int mHeight;
        protected int mWidth;
        protected CharSequence mText;
        protected CharSequence mOldText;

        protected TextPaint mPaint;
        protected TextPaint mOldPaint;

        // 每个字符的宽度集合
        protected List<Float> gapList = new ArrayList<>();
        protected List<Float> oldGapList = new ArrayList<>();

        protected float progress; //  0 ~ 1
        protected float mTextSize;

        protected float oldStartX = 0;

        private float charTime = 300;
        private int mostCount = 20;
        private int mTextHeight;

        private List<CharacterDiffResult> differentList = new ArrayList<>();
        private long duration;

        public EvaporateText(){
            init();
        }

        private void init(){
            mOldText = "123456888";
            mText = "9999999";

            mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setAntiAlias(true);
            mOldPaint = new TextPaint(mPaint);
            mOldPaint.setAntiAlias(true);

            mTextSize = 40;
            mWidth = 600;
            mHeight =300;

            oldStartX = 0;
            //prepareAnimate();
            progress =0;

            int n = mText.length();
            n = n <= 0 ? 1 : n;
            duration = (long) (charTime + charTime / mostCount * (n - 1));
            animateText("564546413");
        }

        @Override
        public void onDraw(Canvas canvas, Paint mPaint) {
            // super.onDraw(canvas);  注释掉 重新绘制文本
            float startX = 0;
            float startY = 100;

            float offset = startX;
            float oldOffset = oldStartX;

            int maxLength = Math.max(mText.length(), mOldText.length());

            for (int i = 0; i < maxLength; i++) {

                // draw old text
                if (i < mOldText.length()) {

                    // pp = progress; 0~1  progress * duration / (charTime + charTime / mostCount * (mText.length() - 1))
                    float pp = progress;

                    mOldPaint.setTextSize(mTextSize);
                    int move = CharacterUtils.needMove(i, differentList);

                    if (move != -1) {
                        // 需要移动的字符 左右平移运动 视觉欺骗并没有上下的运动
                        mOldPaint.setAlpha(255);
                        // * 2f 平移速度
                        float p = pp * 2f;
                        p = p > 1 ? 1 : p;
                        float distX = CharacterUtils.getOffset(i, move, p, startX, oldStartX, gapList, oldGapList);
                        canvas.drawText(mOldText.charAt(i) + "", 0, 1, distX, startY, mOldPaint);
                    } else {
                        mOldPaint.setAlpha((int) ((1 - pp) * 255));
                        float y = startY - pp * mTextHeight;
                        float width = mOldPaint.measureText(mOldText.charAt(i) + "");
                        // (oldGapList.get(i) - width) / 2 值为0   oldOffset + (oldGapList.get(i) - width) / 2
                        canvas.drawText(mOldText.charAt(i) + "", 0, 1, oldOffset, y, mOldPaint);
                    }
                    oldOffset += oldGapList.get(i);
                }

                if (i < mText.length()) {
                    if (!CharacterUtils.stayHere(i, differentList)) {
                        // 渐显效果 延迟
                        int alpha = (int) (255f / charTime * (progress * duration - charTime * i / mostCount));
                        alpha = alpha > 255 ? 255 : alpha;
                        alpha = alpha < 0 ? 0 : alpha;
                        mPaint.setAlpha(alpha);
                        mPaint.setTextSize(mTextSize);

                        //   float pp = progress * duration / (charTime + charTime / mostCount * (mText.length() - 1));
                        float pp = progress;
                        float y = mTextHeight + startY - pp * mTextHeight;

                        float width = mPaint.measureText(mText.charAt(i) + "");
                        canvas.drawText(mText.charAt(i) + "", 0, 1, offset + (gapList.get(i) - width) / 2, y, mPaint);

                    }
                    offset += gapList.get(i);
                }

            }
        }

        public void setProgress(float progress) {
            this.progress = progress;
        }

        public void animateText(CharSequence text) {
            mOldText = mText;
            mText = text;

            prepareAnimate();

            animatePrepare(text);
            animateStart();
        }

        private void animateStart() {
            int n = mText.length();
            n = n <= 0 ? 1 : n;
            duration = (long) (charTime + charTime / mostCount * (n - 1));
        }


        private void animatePrepare(CharSequence text) {
            differentList.clear();
            differentList.addAll(CharacterUtils.diff(mOldText, mText));

            Rect bounds = new Rect();
            mPaint.getTextBounds(mText.toString(), 0, mText.length(), bounds);
            mTextHeight = bounds.height();
        }

        private void prepareAnimate() {
            // 初始化相关数据
            mTextSize =50;
            mPaint.setTextSize(mTextSize);
            mPaint.setColor(color);
            //mPaint.setTypeface();

            gapList.clear();
            for (int i = 0; i < mText.length(); i++) {
                gapList.add(mPaint.measureText(String.valueOf(mText.charAt(i))));
            }

            mOldPaint.setTextSize(mTextSize);
            mOldPaint.setColor(color);
            //mOldPaint.setTypeface(getTypeface());

            oldGapList.clear();
            for (int i = 0; i < mOldText.length(); i++) {
                oldGapList.add(mOldPaint.measureText(String.valueOf(mOldText.charAt(i))));
            }

        }

        @Override
        public void move(int maxWidth, int maxHight) {
            this.progress+=0.1;
            if(progress>1)
                progress=0;
        }

    }

    public static class CharacterUtils {

        /**
         * @param oldText
         * @param newText
         * @return
         */
        public static List<CharacterDiffResult> diff(CharSequence oldText, CharSequence newText) {
            List<CharacterDiffResult> differentList = new ArrayList<>();
            Set<Integer> skip = new HashSet<>();
            for (int i = 0; i < oldText.length(); i++) {
                char c = oldText.charAt(i);
                for (int j = 0; j < newText.length(); j++) {
                    if (!skip.contains(j) && c == newText.charAt(j)) {
                        skip.add(j);
                        CharacterDiffResult different = new CharacterDiffResult();
                        different.c = c;
                        different.fromIndex = i;
                        different.moveIndex = j;
                        differentList.add(different);
                        break;
                    }
                }
            }
            return differentList;
        }

        public static int needMove(int index, List<CharacterDiffResult> differentList) {
            for (CharacterDiffResult different : differentList) {
                if (different.fromIndex == index) {
                    return different.moveIndex;
                }
            }
            return -1;
        }

        public static boolean stayHere(int index, List<CharacterDiffResult> differentList) {
            for (CharacterDiffResult different : differentList) {
                if (different.moveIndex == index) {
                    return true;
                }
            }
            return false;
        }


        // 计算x坐标的位置
        public static float getOffset(int from, int move, float progress, float startX, float oldStartX,
                                      List<Float> gaps, List<Float> oldGaps) {

            float dist = startX;
            for (int i = 0; i < move; i++) {
                dist += gaps.get(i);
            }

            float cur = oldStartX;
            for (int i = 0; i < from; i++) {
                cur += oldGaps.get(i);
            }

            return cur + (dist - cur) * progress;

        }
    }

    public static class CharacterDiffResult {
        public char c;
        public int fromIndex;
        public int moveIndex;
    }
}
